namespace ClassyBlog.Infrastructure.Specs.Unit
{
    using System;

    using Machine.Specifications;
    using NSubstitute;

    using DomainObjects;

    [Subject(typeof(Renderer))]
    public class when_creatingrenderer_with_null_formatters
    {
        static Exception exception;

        Because of = () => exception =
            Catch.Exception(() => new Renderer(null, Substitute.For<IMacroRunner>()));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();
    }

    [Subject(typeof(Renderer))]
    public class when_creating_renderer_with_null_macro_renderer
    {
        static Exception exception;

        Because of = () => exception =
            Catch.Exception(() => new Renderer(new IFormatter[0], null));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();
    }

    [Subject(typeof(Renderer))]
    public class when_trying_render_full_with_null_content
    {
        static Renderer renderer;
        static Exception exception;

        Establish context = () =>
            renderer = new Renderer(
                new IFormatter[0], Substitute.For<IMacroRunner>());

        Because of = () => exception =
            Catch.Exception(() => renderer.RenderFull(null));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();
    }

    [Subject(typeof(Renderer))]
    public class when_trying_render_full_with_no_matching_formatter
    {
        static IContent content;
        static Renderer renderer;
        static Exception exception;

        Establish context = () =>
        {
            content = Substitute.For<IContent>();
            content.Type = "foo";

            renderer = new Renderer(
                new IFormatter[0], Substitute.For<IMacroRunner>());
        };

        Because of = () => exception =
            Catch.Exception(() => renderer.RenderFull(content));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<InvalidOperationException>();
    }

    [Subject(typeof(Renderer))]
    public class when_rendered_full
    {
        static IFormatter formatter;
        static IMacroRunner macroRunner;

        static Renderer renderer;

        Establish context = () =>
        {
            formatter = Substitute.For<IFormatter>();
            formatter.Supports(Arg.Any<string>()).Returns(true);

            macroRunner = Substitute.For<IMacroRunner>();

            renderer = new Renderer(new[] { formatter }, macroRunner);
        };

        Because of = () => renderer.RenderFull(Substitute.For<IContent>());

        It should_formatted_by_matching_formatter = () =>
            formatter.Received().Format(Arg.Any<string>());

        It should_run_macro_runner = () =>
            macroRunner.Received().Run(Arg.Any<string>());
    }

    [Subject(typeof(Renderer))]
    public class when_trying_to_render_summary_with_blank_tag_name
    {
        static Renderer renderer;
        static Exception exception;

        Establish context = () =>
            renderer = new Renderer(
                new IFormatter[0], Substitute.For<IMacroRunner>());

        Because of = () => exception =
            Catch.Exception(() =>
                renderer.RenderSummary(Substitute.For<IContent>(), null));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentException>();
    }

    [Subject(typeof(Renderer))]
    public class when_trying_to_render_summary_without_positive_length
    {
        static Renderer renderer;
        static Exception exception;

        Establish context = () =>
            renderer = new Renderer(
                new IFormatter[0], Substitute.For<IMacroRunner>());

        Because of = () => exception =
            Catch.Exception(() =>
                renderer.RenderSummary(Substitute.For<IContent>(), length:0));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentException>();
    }

    [Subject(typeof(Renderer))]
    public class when_rendered_summary
    {
        static IFormatter formatter;
        static IMacroRunner macroRunner;
        static IContent content;

        static Renderer renderer;
        static string result;

        Establish context = () =>
        {
            formatter = Substitute.For<IFormatter>();
            formatter.Supports(Arg.Any<string>()).Returns(true);
            formatter.Format(Arg.Any<string>()).Returns(c => c.Args()[0]);

            macroRunner = Substitute.For<IMacroRunner>();
            macroRunner.Run(Arg.Any<string>()).Returns(c => c.Args()[0]);

            var body = string.Empty;

            for (var i = 1; i <= 20; i++)
            {
                body += "<p>" + new string('x', 8) + "</p>";
            }

            content = Substitute.For<IContent>();
            content.Body.Returns(body);

            renderer = new Renderer(new[] { formatter }, macroRunner);
        };

        Because of = () => result = renderer.RenderSummary(content);

        It should_not_be_same_as_full = () =>
            result.Length.ShouldBeLessThanOrEqualTo(content.Body.Length);
    }
}